﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Atosenet
{
    public class MultiEntityQueue
    {
        #region 成员

        private const int TASK_CHECK_INTERVAL = 100;

        private Thread _executeThread;
        private AutoResetEvent _resetEvent;

        private TaskPriority _priority = TaskPriority.Normal;

        #endregion


        #region 初始化

        public MultiEntityQueue()
        {
            EntityQueue = new List<IExecutableEntity>();
            _resetEvent = new AutoResetEvent(true);
            EnableThread = true;
        }

        #endregion


        #region 公开函数

        public void Start(int taskInterval)
        {
            _executeThread = new Thread(new ParameterizedThreadStart(ExecuteThread));
            _executeThread.Priority = GetThreadPriority(Priority);
            _executeThread.Name = "[MESingleExecuteQueue] Execute Thread";
            _executeThread.IsBackground = true;
            EnableThread = true;
            _executeThread.Start(taskInterval);
        }

        public void Start()
        {
            Start(TASK_CHECK_INTERVAL);
        }

        public void Stop()
        {
            if (IsStarted)
            {
                EnableThread = false;
            }
        }

        public void ForceStop()
        {
            if (IsStarted)
            {
                EnableThread = false;
                _executeThread.Abort();
            }
        }

        public bool Enqueue(IExecutableEntity entity)
        {
            if (entity != null)
            {
                entity.NewTaskAdded += MultiEntitySingleExecuteQueue_NewTaskAdded;
                EntityQueue.Add(entity);
                _resetEvent.Set();
                return true;
            }
            return false;
        }

        public bool Dequeue(string entityName)
        {
            for (int i = 0; i < EntityQueue.Count; i++)
            {
                if (EntityQueue[i].Name == entityName)
                {
                    EntityQueue[i].NewTaskAdded -= MultiEntitySingleExecuteQueue_NewTaskAdded;
                    EntityQueue.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }

        public void RemoveAll()
        {
            for (int i = EntityQueue.Count - 1; i >= 0; i--)
            {
                EntityQueue[i].NewTaskAdded -= MultiEntitySingleExecuteQueue_NewTaskAdded;
                EntityQueue.RemoveAt(i);
            }
        }

        public bool SetEntityEnable(string name, bool enable)
        {
            int index = EntityQueue.FindIndex((entity) => { return entity.Name == name; });

            if (index >= 0)
            {
                EntityQueue[index].Enable = enable;
                return true;
            }
            return false;
        }

        #endregion


        #region 静态函数



        #endregion


        #region 核心函数

        private void ExecuteThread(object para)
        {
            int interval = (int)para;

            while (EnableThread)
            {
                bool waitFlag = true;

                foreach (IExecutableEntity entity in EntityQueue)
                {
                    if (entity != null && entity.Enable && entity.HasTask)
                    {
                        waitFlag &= entity.ExecuteNext() <= 0;
                        ExecutedCount++;
                    }
                }

                Thread.Sleep(interval);

                if (waitFlag)
                    _resetEvent.WaitOne();
            }
        }

        private ThreadPriority GetThreadPriority(TaskPriority priority)
        {
            ThreadPriority result = ThreadPriority.Normal;

            try
            {
                result = (ThreadPriority)Enum.Parse(typeof(ThreadPriority), priority.ToString(), true);
            }
            catch
            { }
            return result;
        }

        private void MultiEntitySingleExecuteQueue_NewTaskAdded(object sender, EventArgs e)
        {
            _resetEvent.Set();
        }

        #endregion


        #region 属性

        private List<IExecutableEntity> EntityQueue
        {
            get;
            set;
        }

        public long ExecutedCount
        {
            get;
            private set;
        }

        public int CurrentTaskCount
        {
            get
            {
                if (EntityQueue == null)
                    return 0;

                int result = 0;

                foreach (IExecutableEntity entity in EntityQueue)
                    result += entity.CurrentTaskCount;

                return result;
            }
        }

        public TaskPriority Priority
        {
            get { return _priority; }
            set
            {
                if (_priority != value)
                    _priority = value;

                if (_executeThread != null)
                    _executeThread.Priority = GetThreadPriority(value);
            }
        }

        public bool IsStarted
        {
            get { return _executeThread == null ? false : _executeThread.IsAlive; }
        }

        private bool EnableThread
        {
            get;
            set;
        }

        #endregion
    }


    public interface IExecutableEntity
    {
        event EventHandler NewTaskAdded;

        int ExecuteNext();
        
        string Name { get; set; }
        long ExecutedCount { get; }
        int CurrentTaskCount { get; }
        bool HasTask { get; }
        bool Enable { get; set; }
    }


    public abstract class ExecutableEntity<T> : IExecutableEntity
    {
        #region 成员

        public event EventHandler NewTaskAdded;

        #endregion


        #region 初始化

        public ExecutableEntity(string name)
        {
            Name = name;
            ExecuteQueue = new List<T>();
            Enable = true;
        }

        #endregion


        #region 公开函数

        public bool AddItem(T item)
        {
            if (!Enable)
                return false;

            if (VerifyData(item))
            {
                ExecuteQueue.Add(item);
                OnNewTaskAdded();
                return true;
            }
            return false;
        }

        public int ExecuteNext()
        {
            if (!Enable || !HasTask)
                return -1;

            T data = default(T);

            lock (ExecuteQueue)
            {
                data = ExecuteQueue[0];
                ExecuteQueue.RemoveAt(0);
            }

            if (VerifyData(data))
            {
                Executing(data);
            }
            return ExecuteQueue.Count;
        }

        #endregion


        #region 静态函数



        #endregion


        #region 核心函数

        protected abstract bool VerifyData(T data);

        private void Executing(T data)
        {
            try
            {
                if (ExecutingProcess(data))
                    ExecutedCount++;
            }
            catch
            { }
        }

        protected abstract bool ExecutingProcess(T data);

        #endregion


        #region 属性

        public string Name
        {
            get;
            set;
        }

        public long ExecutedCount
        {
            get;
            private set;
        }

        public int CurrentTaskCount
        {
            get { return ExecuteQueue == null ? 0 : ExecuteQueue.Count; }
        }

        public bool HasTask
        {
            get { return ExecuteQueue.Count > 0; }
        }

        public bool Enable
        {
            get;
            set;
        }

        private List<T> ExecuteQueue
        {
            get;
            set;
        }

        #endregion


        #region 事件

        protected void OnNewTaskAdded()
        {
            if (NewTaskAdded != null)
                NewTaskAdded(this, EventArgs.Empty);
        }

        #endregion
    }
}
